use std::collections::HashMap;

use ggez::Context;
use specs::{Entities, Join, ReadStorage, System, Write};

use crate::{
    audio::AudioStore,
    components::{Box, BoxSpot, Position},
    events::{BoxPlacedOnSpot, EntityMoved, Event},
    resources::EventQueue,
};

pub struct EventSystem<'a> {
    pub context: &'a mut Context,
}

impl<'a> System<'a> for EventSystem<'a> {
    type SystemData = (
        Write<'a, EventQueue>,
        Write<'a, AudioStore>,
        Entities<'a>,
        ReadStorage<'a, Box>,
        ReadStorage<'a, BoxSpot>,
        ReadStorage<'a, Position>,
    );

    fn run(&mut self, data: Self::SystemData) {
        let (mut event_queue, mut audio_store, entities, boxes, box_spots, positions) = data;
        let mut new_events = Vec::new();
        for event in event_queue.events.drain(..) {
            match event {
                Event::PlayerHitObstacle => {
                    audio_store.play_sound(self.context, &String::from("wall"));
                }
                Event::EntityMoved(EntityMoved { id }) => {
                    // 判断是否是盒子, 如果是， 判断是否是盒子的位置
                    if let Some(the_box) = boxes.get(entities.entity(id)) {
                        let box_spots_positions = (&box_spots, &positions)
                            .join()
                            .map(|t| ((t.1.x, t.1.y), t.0))
                            .collect::<HashMap<_, _>>();
                        if let Some(box_position) = positions.get(entities.entity(id)) {
                            let box_pos_key = (box_position.x, box_position.y);
                            if let Some(box_spot) = box_spots_positions.get(&box_pos_key) {
                                // 判断是否是盒子的颜色
                                new_events.push(Event::BoxPlacedOnSpot(BoxPlacedOnSpot {
                                    is_correct_spot: box_spot.colour == the_box.colour,
                                }));
                            }
                        }
                    }
                }
                Event::BoxPlacedOnSpot(BoxPlacedOnSpot { is_correct_spot }) => {
                    let sound = if is_correct_spot {
                        String::from("correct")
                    } else {
                        String::from("incorrect")
                    };
                    // play sound
                    audio_store.play_sound(self.context, &sound);
                }
            }
        }
        event_queue.events.append(&mut new_events);
    }
}
